package app

import (
	"crypto/rand"
	"crypto/sha256"
	"encoding/binary"
	"encoding/hex"
	"fmt"
	"time"

	"github.com/wendy512/go-iecp5/asdu"
)

const (
	commonAddr = 1
)

// 设备数据存储结构
type DeviceData struct {
	// 能源调度控制(CA=1)
	Capacity, SOC, MaxPower, ActualPower, RemainTime float32
	TargetPower                                      float32 // 设点命令
	Duration                                         float32 // 设点命令
	ExecCommand                                      bool    // 遥控命令
	ExecStatus                                       int     // 0=停止,1=充电,2=放电

	// 电表数据(CA=2~5)
	Voltage, Current, Power, EnergyIn, EnergyOut float32

	// 储能柜数据(CA=10~N)
	InverterStatus, FireAlarm, ACStatus, WaterAlarm bool
	InverterPower, BMSSOC, BatteryTemp              float32
	DIStatus                                        [16]bool
	DOControl                                       [16]bool
}

// 在MyIec104Server结构体中添加认证相关字段
type MyIec104Server struct {
	data           DeviceData
	authChallenges map[string]time.Time // 存储挑战值和过期时间
	userAccounts   map[string]string    // 存储用户名和密码哈希
	failedAttempts map[string]int       // 存储失败尝试次数
	lockUntil      map[string]time.Time // 存储账户锁定时间
}

// 添加认证类型常量
const (
	S_CH_NA_1 = 81 // 认证挑战
	S_RP_NA_1 = 82 // 认证响应
	S_ER_NA_1 = 87 // 认证错误
	S_US_NA_1 = 90 // 用户状态变更
)

// 添加认证错误代码
const (
	AuthFailed       = 0x01
	UserLocked       = 0x02
	ProtocolMismatch = 0x03
	ChallengeExpired = 0x04
)

func Sha256Calc(data string) string {
	h := sha256.New()
	h.Write([]byte(data))
	hashBytes := h.Sum(nil)
	hash := hex.EncodeToString(hashBytes)
	return hash
}

// 加载用户账户信息
func loadUserAccounts() map[string]string {
	accounts := make(map[string]string)

	// 示例配置 - 实际应从配置文件读取
	accounts["admin"] = "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8"    // password="password"的SHA256哈希
	accounts["operator"] = "a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3" // password="123456"的SHA256哈希

	// 实际实现应从配置文件读取，例如:
	/*
	   config, err := ini.Load("config.ini")
	   if err != nil {
	       log.Fatal("Failed to load config file:", err)
	   }

	   section := config.Section("users")
	   for _, key := range section.Keys() {
	       accounts[key.Name()] = key.Value()
	   }
	*/

	return accounts
}

// 在NewMyIec104Server中初始化认证字段
func NewMyIec104Server() *MyIec104Server {
	return &MyIec104Server{
		data:           DeviceData{},
		authChallenges: make(map[string]time.Time),
		userAccounts:   loadUserAccounts(), // 从配置文件加载用户账户
		failedAttempts: make(map[string]int),
		lockUntil:      make(map[string]time.Time),
	}
}

// 处理认证挑战请求
func (s *MyIec104Server) handleAuthChallenge() ([]byte, error) {
	challenge := generateChallenge()
	s.authChallenges[string(challenge)] = time.Now().Add(3 * time.Second)
	return challenge, nil
}

// 认证响应数据结构
type AuthResponse struct {
	UsernameLen uint8    // 用户名长度 (1-32字节)
	Username    [32]byte // UTF-8格式用户名
	Response    [32]byte // HMAC-SHA256(挑战值|密码)
}

// 解析认证响应数据
func parseAuthResponse(data []byte) (*AuthResponse, error) {
	if len(data) < 1+32+32 { // 用户名长度 + 用户名 + 响应
		return nil, fmt.Errorf("invalid auth response length")
	}

	resp := &AuthResponse{
		UsernameLen: data[0],
	}

	copy(resp.Username[:], data[1:33])
	copy(resp.Response[:], data[33:65])

	return resp, nil
}

// 处理认证响应
func (s *MyIec104Server) handleAuthResponse(data []byte) (uint8, error) {
	var resp AuthResponse
	// 解析响应数据
	// 验证挑战值、用户名和密码
	// 返回错误码或成功状态
	fmt.Println("handle auth response", resp)
	return 1, nil
}

// 生成挑战值
func generateChallenge() []byte {
	randBytes := make([]byte, 4)
	rand.Read(randBytes)
	timestamp := make([]byte, 4)
	binary.BigEndian.PutUint32(timestamp, uint32(time.Now().Unix()))
	return append(randBytes, timestamp...)
}

func (ms *MyIec104Server) OnCounterInterrogation(conn asdu.Connect, pack *asdu.ASDU, quality asdu.QualifierCountCall) error {
	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
	// TODO
	_ = asdu.CounterInterrogationCmd(conn, asdu.CauseOfTransmission{Cause: asdu.Activation}, commonAddr, asdu.QualifierCountCall{asdu.QCCGroup1, asdu.QCCFrzRead})
	_ = pack.SendReplyMirror(conn, asdu.ActivationTerm)
	return nil
}

func (ms *MyIec104Server) OnRead(conn asdu.Connect, pack *asdu.ASDU, addr asdu.InfoObjAddr) error {
	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
	// TODO
	_ = asdu.Single(conn, false, asdu.CauseOfTransmission{Cause: asdu.InterrogatedByStation}, commonAddr, asdu.SinglePointInfo{
		Ioa:   addr,
		Value: true,
		Qds:   asdu.QDSGood,
	})
	_ = pack.SendReplyMirror(conn, asdu.ActivationTerm)
	return nil
}

func (ms *MyIec104Server) OnClockSync(conn asdu.Connect, pack *asdu.ASDU, tm time.Time) error {
	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
	now := time.Now()
	_ = asdu.ClockSynchronizationCmd(conn, asdu.CauseOfTransmission{Cause: asdu.Activation}, commonAddr, now)
	_ = pack.SendReplyMirror(conn, asdu.ActivationTerm)
	return nil
}

func (ms *MyIec104Server) OnResetProcess(conn asdu.Connect, pack *asdu.ASDU, quality asdu.QualifierOfResetProcessCmd) error {
	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
	// TODO
	_ = asdu.ResetProcessCmd(conn, asdu.CauseOfTransmission{Cause: asdu.Activation}, commonAddr, asdu.QPRGeneralRest)
	_ = pack.SendReplyMirror(conn, asdu.ActivationTerm)
	return nil
}

func (ms *MyIec104Server) OnDelayAcquisition(conn asdu.Connect, pack *asdu.ASDU, msec uint16) error {
	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
	// TODO
	_ = asdu.DelayAcquireCommand(conn, asdu.CauseOfTransmission{Cause: asdu.Activation}, commonAddr, msec)
	_ = pack.SendReplyMirror(conn, asdu.ActivationTerm)
	return nil
}

//func (ms *MyIec104Server) OnASDU(conn asdu.Connect, pack *asdu.ASDU) error {
//	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
//	// TODO
//	cmd := pack.GetSingleCmd()
//	_ = asdu.SingleCmd(conn, pack.Type, pack.Coa, pack.CommonAddr, asdu.SingleCommandInfo{
//		Ioa:   cmd.Ioa,
//		Value: cmd.Value,
//		Qoc:   cmd.Qoc,
//	})
//	_ = pack.SendReplyMirror(conn, asdu.ActivationCon)
//	return nil
//}

func (s *MyIec104Server) OnInterrogation(conn asdu.Connect, pack *asdu.ASDU, qoi asdu.QualifierOfInterrogation) error {
	ca := pack.CommonAddr
	// 根据公共地址返回对应数据
	if ca == 1 {
		// 能源调度控制数据
		asdu.MeasuredValueFloat(conn, false, asdu.CauseOfTransmission{Cause: asdu.InterrogatedByStation},
			ca, asdu.MeasuredValueFloatInfo{Ioa: 1, Value: s.data.Capacity})
		// ... 其他IOA数据
	} else if ca >= 10 {
		// 储能柜数据
		asdu.Single(conn, false, asdu.CauseOfTransmission{Cause: asdu.InterrogatedByStation},
			ca, asdu.SinglePointInfo{Ioa: 1, Value: s.data.InverterStatus, Qds: asdu.QDSGood})
	}
	return nil
}

func (s *MyIec104Server) OnASDU(conn asdu.Connect, pack *asdu.ASDU) error {
	// 处理遥控和设点命令
	switch pack.Type {
	case asdu.C_SC_NA_1: // 单点遥控
		cmd := pack.GetSingleCmd()
		if cmd.Ioa == 6 { // 执行命令
			s.data.ExecCommand = cmd.Value
		}
	case asdu.C_SE_NC_1: // 设点命令
		sp := pack.GetSetpointFloatCmd()
		switch sp.Ioa {
		case 4: // 目标功率
			s.data.TargetPower = sp.Value
		case 5: // 持续时间
			s.data.Duration = sp.Value
		}
	}
	return nil
}
